package com.hitqz.robot.biz.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hitqz.robot.api.business.entity.RobotJobEntity;
import com.hitqz.robot.api.business.vo.RobotJobCalendarDayVo;
import com.hitqz.robot.api.business.vo.RobotJobCalendarDetailVo;
import com.hitqz.robot.api.business.vo.RobotJobCalendarMonthVo;
import com.hitqz.robot.api.dispatch.protocol.dto.FormConfigModalDto;
import com.hitqz.robot.api.dispatch.protocol.dto.FormFieldConfigModalDto;
import com.hitqz.robot.biz.mapper.RobotJobMapper;
import com.hitqz.robot.biz.service.RobotJobService;
import org.quartz.CronExpression;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.*;

/**
 * 机器人任务管理表
 *
 * @author wengyongxin
 * @date 2024-05-31 15:41:27
 */
@Service
public class RobotJobServiceImpl extends ServiceImpl<RobotJobMapper, RobotJobEntity> implements RobotJobService {
    @Override
    public List<RobotJobCalendarMonthVo> calendarMonth(DateTime date) {
        // 查询任务
        List<RobotJobEntity> list = baseMapper.selectList(Wrappers.<RobotJobEntity>lambdaQuery().eq(RobotJobEntity::getEnable,1));
        // 筛选当月会执行的任务 减少后面循环次数
        list = list.stream().filter(f->this.isCronMatchToMonth(f.getCron(),date)).toList();
        // 初始化日期任务映射，遍历本月的每一天
        Map<String, List<RobotJobCalendarDetailVo>> dateJobsMap = new HashMap<>();
        DateTime currentDate = DateUtil.beginOfMonth(date);
        DateTime endOfMonth = DateUtil.endOfMonth(date);
        while (!currentDate.isAfter(endOfMonth)) {
            // 检查是否有任务在当前日期
            for (RobotJobEntity job : list) {
                if (this.isCronMatchToDay(job.getCron(),currentDate)) {
                    RobotJobCalendarDetailVo detailVo = new RobotJobCalendarDetailVo();
                    detailVo.setId(job.getId());
                    detailVo.setName(job.getName());
                    FormConfigModalDto formConfigModalDto = JSONObject.parseObject(job.getContent(), FormConfigModalDto.class);
                    StringBuffer stringBuffer = new StringBuffer();
                    for (FormFieldConfigModalDto modalDto : formConfigModalDto.getFields()) {
                        String currentValue = modalDto.getCurrentValue();
                        List<String> optionsList = modalDto.getOptions();
                        if (optionsList != null) {
                            List<Map> parsedOptions = optionsList.stream()
                                    .map(option -> JSONObject.parseObject(option, Map.class))
                                    .toList();
                            for (Map<String, Object> options : parsedOptions) {
                                Optional<String> valueOpt = Optional.ofNullable(options.get("value")).map(Object::toString);
                                Optional<String> labelOpt = Optional.ofNullable(options.get("label")).map(Object::toString);
                                if (valueOpt.isPresent() && Objects.equals(valueOpt.get(), currentValue) && labelOpt.isPresent()) {
                                    currentValue = labelOpt.get();
                                    break;
                                }
                            }
                        }
                        stringBuffer.append(modalDto.getLabel() + ":" + currentValue + ";");
                    }
                    detailVo.setTaskContent(stringBuffer.toString());
                    //todo 先统一样式后续再处理
                    detailVo.setStatus(1);
                    dateJobsMap.computeIfAbsent(DateUtil.format(currentDate,"yyyy-MM-dd"), k -> new ArrayList<>()).add(detailVo);
                }
            }
            // 日期加一天
            currentDate = currentDate.offset(DateField.DAY_OF_MONTH,1);
        }
        // 将日期和对应的任务信息填充到响应对象中
        List<RobotJobCalendarMonthVo> monthVoList = new ArrayList<>();
        for (Map.Entry<String, List<RobotJobCalendarDetailVo>> entry : dateJobsMap.entrySet()) {
            RobotJobCalendarMonthVo dayVo = new RobotJobCalendarMonthVo();
            dayVo.setDate(entry.getKey());
            dayVo.setJobs(entry.getValue());
            dayVo.setTaskNumber(entry.getValue().size());
            monthVoList.add(dayVo);
        }
        //按日期排序
        monthVoList.sort(Comparator.comparing(RobotJobCalendarMonthVo::getDate));
        return monthVoList;
    }

    @Override
    public List<RobotJobCalendarMonthVo> calendarMonthNew(DateTime date) {
        return this.calendarMonth(date);
    }

    @Override
    public List<RobotJobCalendarDayVo> calendarDay(DateTime date) {
        // 查询任务，只要任务的开始或结束时间在该日范围内即返回
        List<RobotJobEntity> list = baseMapper.selectList(Wrappers.<RobotJobEntity>lambdaQuery().eq(RobotJobEntity::getEnable,1));
        // 筛选当天会执行的任务 减少后面循环次数
        list = list.stream().filter(f->this.isCronMatchToDay(f.getCron(),date)).toList();
        // 初始化日期任务映射，遍历一天的每一小时
        Map<String, List<RobotJobCalendarDetailVo>> timeJobsMap = new HashMap<>();
        DateTime currentDate = DateUtil.beginOfDay(date);
        DateTime endDate = DateUtil.endOfDay(date);
        while (!currentDate.isAfter(endDate)) {
            // 获取当前小时的时间段（HH:mm:ss）
            String currentHour = currentDate.toString("HH:mm");
            // 检查是否有任务在当前小时内
            for (RobotJobEntity job : list) {
                // 判断任务是否在当前小时内有效
                if (this.isCronMatchToHor(job.getCron(), currentDate)) {
                    RobotJobCalendarDetailVo detailVo = new RobotJobCalendarDetailVo();
                    detailVo.setId(job.getId());
                    detailVo.setName(job.getName());
                    //todo 先统一样式后续再处理
                    FormConfigModalDto formConfigModalDto = JSONObject.parseObject(job.getContent(), FormConfigModalDto.class);
                    StringBuffer stringBuffer = new StringBuffer();
                    for (FormFieldConfigModalDto modalDto : formConfigModalDto.getFields()) {
                        String currentValue = modalDto.getCurrentValue();
                        List<String> optionsList = modalDto.getOptions();
                        if (optionsList != null) {
                            List<Map> parsedOptions = optionsList.stream()
                                    .map(option -> JSONObject.parseObject(option, Map.class))
                                    .toList();
                            for (Map<String, Object> options : parsedOptions) {
                                Optional<String> valueOpt = Optional.ofNullable(options.get("value")).map(Object::toString);
                                Optional<String> labelOpt = Optional.ofNullable(options.get("label")).map(Object::toString);
                                if (valueOpt.isPresent() && Objects.equals(valueOpt.get(), currentValue) && labelOpt.isPresent()) {
                                    currentValue = labelOpt.get();
                                    break;
                                }
                            }
                        }
                        stringBuffer.append(modalDto.getLabel() + ":" + currentValue + ";");
                    }
                    detailVo.setTaskContent(stringBuffer.toString());
                    detailVo.setStatus(1);
                    timeJobsMap.computeIfAbsent(currentHour, k -> new ArrayList<>()).add(detailVo);
                }
            }
            // 小时加一
            currentDate = currentDate.offset(DateField.HOUR_OF_DAY, 1);
        }
        // 将时间和对应的任务信息填充到响应对象中
        List<RobotJobCalendarDayVo> dayVoList = new ArrayList<>();
        for (Map.Entry<String, List<RobotJobCalendarDetailVo>> entry : timeJobsMap.entrySet()) {
            RobotJobCalendarDayVo dayVo = new RobotJobCalendarDayVo();
            dayVo.setTime(entry.getKey());
            dayVo.setJobs(entry.getValue());
            dayVo.setTaskNumber(entry.getValue().size());
            dayVoList.add(dayVo);
        }
        //按日期排序
        dayVoList.sort(Comparator.comparing(RobotJobCalendarDayVo::getTime));
        return dayVoList;
    }

    @Override
    public List<RobotJobCalendarDayVo> calendarDayNew(DateTime date) {
        return this.calendarDay(date);
    }

    /**
     * 判断当前时间是否符合cron表达式
     */
    private boolean isCronMatchToHor(String cron, DateTime currentHour)  {
        // 判断当前时间是否符合 cron 表达式
        CronExpression cronExpression = null;
        currentHour = DateUtil.beginOfHour(currentHour);
        try {
            String[] split = cron.trim().split(" ");
            split[0] = "0";//不判断秒
            split[1] = "0";//不判断分
            cron = String.join(" ", split);
            cronExpression = new CronExpression(cron);
        } catch (ParseException e) {
            log.error("parse cron error", e);
            return false;
        }
        return cronExpression.isSatisfiedBy(currentHour.toJdkDate());
    }

    private boolean isCronMatchToDay(String cron, DateTime currentDay)  {
        // 判断当前时间是否符合 cron 表达式
        CronExpression cronExpression = null;
        currentDay = DateUtil.beginOfDay(currentDay);
        try {
            String[] split = cron.trim().split(" ");
            split[0] = "0";//不判断秒
            split[1] = "0";//不判断分
            split[2] = "0";//不判断时
            cron = String.join(" ", split);
            cronExpression = new CronExpression(cron);
        } catch (ParseException e) {
            log.error("parse cron error", e);
            return false;
        }
        return cronExpression.isSatisfiedBy(currentDay.toJdkDate());
    }

    private boolean isCronMatchToMonth(String cron, DateTime currentMonth)  {
        // 判断当前时间是否符合 cron 表达式
        CronExpression cronExpression = null;
        currentMonth = DateUtil.beginOfMonth(currentMonth);
        try {
            String[] split = cron.trim().split(" ");
            split[0] = "0";//不判断秒
            split[1] = "0";//不判断分
            split[2] = "0";//不判断时
            split[2] = "0";//不判断日
            cron = String.join(" ", split);
            cronExpression = new CronExpression(cron);
        } catch (ParseException e) {
            log.error("parse cron error", e);
            return false;
        }
        return cronExpression.isSatisfiedBy(currentMonth.toJdkDate());
    }




}